package com.gitee.wsl.struct.generator.sample

import com.gitee.wsl.ext.base.currentTimeMillis
import com.gitee.wsl.ext.string.toBinaryString
import com.gitee.wsl.result.tran.onFailure
import com.gitee.wsl.result.tran.onSuccess
import com.gitee.wsl.time.T
import com.gitee.wsl.time.toEpochMilliseconds
import timber.log.Timber
import kotlin.random.Random


/**
 * 卡号生成器接口
 *
 * @author liuzhaoming
 * @date 2021-12-14 17:17
 */
interface CardIdGeneratorable {
    /**
     * 校验验证码
     *
     * @param id             ID
     * @param startTimeStamp 起始时间戳
     * @param timeBits       时间bit位数
     * @param timeOffset     时间偏移位数
     * @param validationBits 验证码bit位数
     * @param maxCode        最大校验码
     * @return 验证结果，合法返回true，反之false
     */
    fun validateCode(
        id: Long,
        startTimeStamp: Long,
        timeBits: Int,
        timeOffset: Int,
        validationBits: Int,
        maxCode: Int,
    ): Boolean {
        val bitString: String = id.toString().toBinaryString()
        val bitLength = bitString.length
        val codeBitString = bitString.substring(bitLength - validationBits)
        val validationCode = codeBitString.toInt(2)
        val originId = id - validationCode
        if (validationCode != getValidationCode(originId, maxCode)) {
            return false
        }

        val timestamp = bitString.substring(bitLength - timeOffset - timeBits, bitLength - timeOffset).toLong(2)
        val currentStamp: Long = currentTimeMillis / 1000 - startTimeStamp
        val timeDelta = currentStamp - timestamp
        return timeDelta > -3600
    }

    /**
     * 生成一个随机数作为sequence的起始数
     *
     * @return sequence起始数
     */
    fun randomSequence(): Long {
        return Random.nextLong(10)
    }

    companion object{
        /**
         * 获取校验码
         *
         * @param originId 原始数字
         * @param maxCode  最大校验码
         * @return 校验码
         */
        fun getValidationCode(originId: Long, maxCode: Int): Int {
            val strOriginId = originId.toString()
            val numbers = IntArray(strOriginId.length)
            run {
                var i = 0
                val length = strOriginId.length
                while (i < length) {
                    numbers[i] = strOriginId[i].digitToInt()
                    i++
                }
            }
            var i = numbers.size - 2
            while (i >= 0) {
                numbers[i] = numbers[i] shl 1
                numbers[i] = numbers[i] / 10 + numbers[i] % 10
                i -= 2
            }

            var validationCode = 0
            for (number in numbers) {
                validationCode += number
            }
            validationCode *= 9
            return validationCode % maxCode
        }

        /**
         * 获取校验码
         *
         * @param originId 原始数字
         * @param maxCode  最大校验码
         * @return 校验码
         */
        fun getValidationCode(originId: Long, maxCode: Long): Long {
            val strOriginId = originId.toString()
            val numbers = IntArray(strOriginId.length)
            run {
                var i = 0
                val length = strOriginId.length
                while (i < length) {
                    numbers[i] = strOriginId[i].digitToInt()
                    i++
                }
            }
            var i = numbers.size - 2
            while (i >= 0) {
                numbers[i] = numbers[i] shl 1
                numbers[i] = numbers[i] / 10 + numbers[i] % 10
                i -= 2
            }

            var validationCode = 0L
            for (number in numbers) {
                validationCode += number.toLong()
            }
            validationCode *= 9
            return validationCode % maxCode
        }

        /**
         * 获取起始时间戳(单位秒)
         *
         * @param dateStr 时间字符串，格式为"yyyy-MM-dd HH:mm:ss"
         * @return 时间戳
         */
        fun getTimeStampSecond(dateStr: String): Long {

            var result = 1546272000L

            T.parseDateTime(dateStr).onSuccess {
                result= it.toEpochMilliseconds()/1000
            }.onFailure {
                Timber.e("Cannot get time stamp string:$dateStr, the invalid date format is yyyy-MM-dd HH:mm:ss, please check! $it")
            }

            return result

            /*try {
                return T.parse(dateStr).toLocalDateTime().toEpochMilliseconds()/1000
            } catch (e: Exception) {
                Timber.e("Cannot get time stamp string, the invalid date format is yyyy-MM-dd HH:mm:ss, please check! $e")
                return 1546272000L
            }*/
        }
    }

}
